package org.xteam.box2text;

import java.util.List;

import org.xteam.box2text.box.Box;
import org.xteam.box2text.box.HOVOperator;
import org.xteam.box2text.box.HOperator;
import org.xteam.box2text.box.HVOperator;
import org.xteam.box2text.box.IOperator;
import org.xteam.box2text.box.ROperator;
import org.xteam.box2text.box.SLOperator;
import org.xteam.box2text.box.TextBox;
import org.xteam.box2text.box.VOperator;
import org.xteam.box2text.box.WDOperator;
import org.xteam.box2text.box.util.BoxSwitch;

public class BoxWidth extends BoxSwitch<Integer> {

	private Frame frame;
	
	public BoxWidth(Frame frame) {
		this.frame = frame;
	}

	public Integer caseTextBox(TextBox box) {
		return box.getContents().length();
	}
	
	public Integer caseHOperator(HOperator box) {
		int sum = 0;
		boolean isFirst = true;
		for (Box arg : box.getArguments()) {
			int val = doSwitch(arg);
			if (val != 0) {
				if (isFirst) {
					isFirst = false;
					sum = doSwitch(arg);
				} else {
					sum += frame.getHs(box.getOptions()) + val;
				}
			}
		}
		return sum;
	}
	
	public Integer caseVOperator(VOperator box) {
		return verticalWidth(box.getArguments());
	}
	
	public Integer caseHVOperator(HVOperator box) {
		return verticalWidth(box.getArguments());
	}
	
	public Integer caseHOVOperator(HOVOperator box) {
		return verticalWidth(box.getArguments());
	}
	
	public int verticalWidth(List<Box> arguments) {
		int max = 0;
		for (Box arg : arguments) {
			int w = doSwitch(arg);
			if (w > max)
				max = w;
		}
		return max;
	}
	
	public Integer caseWDOperator(WDOperator box) {
		return width(box.getArguments(), frame);
	}
	
	public Integer caseIOperator(IOperator box) {
		return width(box.getArguments(), frame);
	}
	
	public Integer caseSLOperator(SLOperator box) {
		throw new RuntimeException("SL box should have been removed");
	}
	
	public Integer caseROperator(ROperator box) {
		throw new RuntimeException("R box should have been removed");
	}
	
	protected int width(List<Box> boxes, Frame frame) {
		if (boxes.isEmpty())
			return 0;
		if (boxes.size() > 1)
			throw new RuntimeException("operator should only contain one element");
		return doSwitch(boxes.get(0));
	}

	public static int width(Box b, Frame f) {
		BoxWidth bw = new BoxWidth(f);
		return bw.doSwitch(b);
	}
	
}
